import qs from 'qs';
import { RequestResultError, authError, unknownError, noFoundError } from './result';
import type { RequestOptions, RequestPayload, RequestResult, RequestVariablesType } from './types';

export class Request {
  private options: RequestOptions;

  constructor(options: RequestOptions) {
    this.options = options;
    this.send = this.send.bind(this);
  }

  get apiUrl() {
    return this.options.apiUrl;
  }

  private getBody = (data?: RequestVariablesType) => {
    const f = data instanceof FormData
    return f ? data : JSON.stringify(data);
  }

  public async send<T = any>(path: string, payload: RequestPayload) {
    const {
      token,
      variables = {},
      skipToken = false
    } = payload;

    const url = [this.apiUrl, path].join('');
    const getHeaders = this.options.getHeaders;

    let headers: Record<string, any> = {
      'content-type': 'application/json'
    };

    if (!skipToken) {
      if (token) {
        headers.Authorization = `Bearer ${token}`;
      } else {
        return Promise.reject(authError);
      }
    }

    const body = this.getBody(variables);
    headers = getHeaders?.(headers) || headers;

    console.log('headers->', headers);
    console.log('body->', body);

    try {
      const result = await fetch(url, {
        body,
        headers,
        method: 'POST'
      });

      switch (result.status) {
        case authError.code: {
          return Promise.reject(authError);
        }
        case noFoundError.code: {
          return Promise.reject(noFoundError);
        }
      }

      const json = await result.json() as RequestResult<T>;
      console.log('results->', json);

      if (json.error) {
        const error = new RequestResultError(unknownError.code, json.error);
        return Promise.reject(error);
      } else {
        return Promise.resolve(json.data!);
      }
    } catch (err) {
      console.log('error->', err);
      return Promise.reject(unknownError);
    }
  }
}